////////////////////////////////////////////////////////////////////////////////////         
// Final Project AIT Racing Car
//
// Interaction:
// Press space and tab to select a control point.
// Press the right/left to turn car.
// Press the up/down arrow keys to move car forward or backward.
// Press the a, A keys to rotate the viewpoint about Y-Axis.
// Press the s, S keys to move the view point up or down.
// Press the d, D keys to zoom out or zoom in the viewpoint.
//
//////////////////////////////////////////////////////////////////////////////////// 

#include <GL/glut.h>
#include <iostream.h>
#include <fstream.h>
#include <math.h>
#include <stdio.h>
#include "loader.h"

#define PI 3.14159265
static int animationPeriod = 100; // Time interval between frames.
static int isForce = 0;
static float xpos = 0.0;
static float zpos = 0.0;
static int cameraMode=0;
static float deltaAngle=0.0;
static float deltaMove=0.0;
static float carAngle=0.0;
static float rpm=0.0;
static bool isLoad=false;
// Begin globals.
// Initial control points.

static float controlPoints[8][2][3]=
{
	{{-2.6,-1,7},{-3.15,-0.9,6.2}},
	{{-3.3,2.1,5},{-3.05,2.6,5}},
	{{-3.2,1.49012e-009,3},{-2.25,-3.2,3}},
	{{-0.800001,-1.6,1},{-2.55,-1,1}},
	{{-3,-1.7,-1},{-2.65,-2.8,-4}},
	{{-3,3.2,-3},{-3.75,4.7,-5}},
	{{-3,0,-5},{-3.05,-1.1,-5}},
	{{-3,-0.2,-5.5},{-3.0,-0.8,-5.5}}	
};

static float controlPoints0[8][2][3]=
{
	{{-2.6,-1,7},{-3.15,-0.9,6.2}},
	{{-3.3,2.1,5},{-3.05,2.6,5}},
	{{-3.2,1.49012e-009,3},{-2.25,-3.2,3}},
	{{-0.800001,-1.6,1},{-2.55,-1,1}},
	{{-3,-1.7,-1},{-2.65,-2.8,-4}},
	{{-3,3.2,-3},{-3.75,4.7,-5}},
	{{-3,0,-5},{-3.05,-1.1,-5}},
	{{-3,-0.2,-5.5},{-3.00,-0.8,-5.5}}	
};

static float controlPoints1[8][6][3] = 
{
	{{-2.6,-1,7},{-1.25,-1,7},{-0.25,-1,7},{0.25,-1,7},{1.25,-1,7},{2.6,-1,7}},
	{{-3.3,2.1,5},{-1.75,0,5},{-0.25,1.8,5},{0.25,1.8,5},{1.75,0,5},{3.3,2.1,5}},
	{{-3.2,1.49012e-009,3},{-1.75,0.6,3},{-0.25,0,3},{0.25,0,3},{1.75,0,3},{3.2,0,3}},
	{{-0.800001,-1.6,1},{-1.75,9.2,1},{-0.25,-1.2,1},{0.25,-1.2,1},{1.75,9.1,1},{0.800001,-1.6,1}},
	{{-3,-1.7,-1},{-1.75,0,-1},{-0.25,5.8,-1},{0.25,5.8,-1},{1.75,0,-1},{3,-1.7,-1}},
	{{-3,3.2,-3},{-1.75,0,-3},{-0.25,0,-3},{0.25,0,-3},{1.75,0,-3},{3,3.2,-3}},
	{{-3,0,-5},{-1.75,0.2,-5},{-0.25,0.3,-5},{0.25,0.3,-5},{1.75,0.2,-5},{3,0,-5}},
	{{-3,-0.2,-5.5},{-1.75,0,-5.9},{-0.25,0,-6.1},{0.25,0,-6.1},{1.75,0,-5.9},{3,-0.2,-5.5}}
};

static float controlPoints2[3][6][3]=
{
	{{-2.5,-0.8,-2.9},{-2.45,0.4,-2.9},{-0.25,1.3411e-008,-2.9},{0.25,1.63913e-008,-2.9},{2.45,0.4,-2.9},{2.5,-0.8,-2.9}},
	{{-2.5,-2,-2.1},{-2.45,-1,-2.1},{-0.25,-1,-2.1},{0.25,-1,-2.1},{2.45,-1,-2.1},{2.5,-2,-2.1}},
	{{-2.5,-1,-3},{-2.45,0,-3},{-0.25,-0.5,-3},{0.25,-0.5,-3},{2.45,0,-3},{2.5,-1,-3}}

};

static float controlPoints3[2][6][3]=
{
	{{-3,1,-1},{-1.75,1.1,-1.4},{-0.25,1.2,-1.6},{0.25,1.2,-1.6},{1.75,1.1,-1.4},{3,1,-1}},
	{{-3,0.4,-1},{-1.75,0.3,-1.4},{-0.25,0.3,-1.6},{0.25,0.3,-1.6},{1.75,0.3,-1.4},{3,0.4,-1}}
};

static float Xangle = 0.0, Yangle = 0.0, Zangle = 0.0; // Angles to rotate canoe.
static int rowCount = 0, columnCount = 0; // Indexes of selected control point.
static float vertices[10000];
static float vertices2[10000];
static float vertices3[10000];
static float vertices4[10000];
static float vertices5[10000];
static float vertices6[10000];
static unsigned char stripIndices[10000];
static int numVertices = 200;
//Global Radius for Front Wheel
static float R = 0.8;
static float R2 = 0.6;
static float angleY = 0.0;
//Global Radius for Rear Wheel
static float R3 = 1.0;
static float R4 = 0.8;
static float xVal =-50.0 , yVal= 77.0 , zVal=12.0;
// End globals.
static float acceleration = 0.05;
static float acceleration2 = 0.05;
static float velocity=0.0;
static float velocity2=0.0; 
static int direction = 0;
static float latitude=0.0;
static float longitude=0.0;
static float angle=0.0;
static float angle2=0.0;
static float s = 0.0;
static int font=(int)GLUT_BITMAP_8_BY_13; // Font selection.
static char theStringBuffer[10]; // String buffer.

static float q = 1.0; // Blue ambient reflectance.
static float w = 1.0; // Blue diffuse reflectance.
static float r = 1.0; // White specular reflectance. 
static float h = 50.0; // Shininess.
static float e = 0.0; // Blue emittance.
static float g = 0.0; // Quadratic attenuation factor.


static float muR=0.015; //Coeficient of Rolling Friction
static float omegaE=1000.0;
static float redline=7200;//rpm
static float finalDriveRatio=3.44;
static int gearNumber=1;
static int numberOfGears =5;
static float gearRatio[5+1]={0.0,3.82,2.20,1.52,1.22,1.02};
static float v,vx,vy,vz;

static float mass = 1393;//kg
static float G= -9.81;
static float area = 1.94;//m^2
static float Cd = 0.31;
static float wheelRadius = 0.3186;

static Model *obj;
static Model *wheel;
/////////////////////////////////////////////////////////////////////////////////////////////


Vertex::Vertex (float xVal, float yVal, float zVal) 
	{
		data[0] = xVal;
		data[1] = yVal;
		data[2] = zVal;
	};

Face::Face (int vaVal, int vnaVal, int vtaVal, int vbVal, int vnbVal, int vtbVal, int vcVal, int vncVal, int vtcVal) 
	{
		va = vaVal;
		vb = vbVal;
		vc = vcVal;
		vna = vnaVal;
		vnb = vnbVal;
		vnc = vncVal;
		vta = vtaVal;
		vtb = vtbVal;
		vtc = vtcVal;
	};


Model::Model() 
	  {    
			// Insert dummy elements.
			v.push_back (new Vertex (0.0, 0.0, 0.0));
			vn.push_back (new Vertex (0.0, 0.0, 0.0));
			vt.push_back (new Vertex (0.0, 0.0, 0.0));
	  }

void Model::readObj (char *filename) 
	  {
		char buffer[128];
		int va, vb, vc, vna, vnb, vnc, vta, vtb, vtc;
		float x, y, z;
		FILE * file;
    
		// Open file.
		file = fopen (filename, "r");

		if (!file)  
		  {
			cout << "readObj () failed: Can't open file: " << filename << endl;
			exit (1);
		  }

		while (fscanf (file, "%s", buffer) != EOF)
		  {
			switch (buffer[0])
			  {
			  case '#':
				// Ignore the read line.
				fgets (buffer, sizeof (buffer), file);
				break;
			  case 'v':
				switch (buffer[1])
				  {
				  case '\0':
					fscanf (file, "%f %f %f", &x, &y, &z);
					v.push_back (new Vertex (x, y, z));
					break;
				  case 'n':
					fscanf (file, "%f %f %f", &x, &y, &z);
					vn.push_back (new Vertex (x, y, z));
					break;
				  case 't':
					fscanf (file, "%f %f %f", &x, &y, &z);
					vt.push_back (new Vertex (x, y, z));
					break;
				  }
				break;
			  case 'u':
				// Ignore the read line.
				fgets (buffer, sizeof (buffer), file);
				break;
			  case 'g':
				// Ignore the read line.
				fgets (buffer, sizeof (buffer), file);
				break;
			  case 'f':
				fscanf (file, "%d/%d/%d %d/%d/%d %d/%d/%d", &va, &vta, &vna, &vb, &vtb, &vnb, &vc, &vtc, &vnc);
				f.push_back (new Face (va, vna, vta, vb, vnb, vtb, vc, vnc, vtc));
				break;
			  default:
				// Ignore the read line.
				fgets (buffer, sizeof (buffer), file);
				break;
			  }
		  }
			

		// Close file.
		fclose (file);
	  }

	  void Model::draw(void) 
	  {
		glBegin (GL_TRIANGLES);

		for (int i = 0; i < f.size (); i++)      
		  {

			glTexCoord3fv((vt.at ((f.at (i))->vta))->data);
			glNormal3fv ((vn.at ((f.at (i))->vna))->data);
			glVertex3fv ((v.at ((f.at (i))->va))->data);

			glTexCoord3fv((vt.at ((f.at (i))->vtb))->data);
			glNormal3fv ((vn.at ((f.at (i))->vnb))->data);
			glVertex3fv ((v.at ((f.at (i))->vb))->data);

			glTexCoord3fv((vt.at ((f.at (i))->vtc))->data);
			glNormal3fv ((vn.at ((f.at (i))->vnc))->data);
			glVertex3fv ((v.at ((f.at (i))->vc))->data);
		  }

		glEnd ();
	  }

/////////////////////////////////////////////////////////////////////////////////////////////


void shiftGear(int shift)
{
	if(shift+gearNumber> numberOfGears)
	{
		return;
	}else if(shift+gearNumber<1)
	{
		return;
	}else
	{
		float oldGearRatio,newGearRatio;
		oldGearRatio = gearRatio[gearNumber];
		gearNumber+=gearNumber+shift;
		newGearRatio = gearRatio[gearNumber];
		omegaE=omegaE*(newGearRatio/oldGearRatio);
	}	
	return;
}





/*void class Car{
	public:
		float weight;
		float centerOfMass;
		float heightOfCG;
		float breakingForce;
		float wheelbase;
		float fractionOfWeight;
		float lf , lr;
		float height;
		float power;
		float vx,vy,vz;
		float a;
		float wheelAngle;
		float carAngle;
		float widthSuspensionAngle;
		float longSuspensionAngle;
		float gear;
	public:
		float accelerate(float u);
};*/

void createFrontWheel()
{
	int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices[i*6] = R * cos(t);
		 vertices[i*6+1] = R * sin(t);
		 vertices[i*6+2] = 0;
		 vertices[i*6+3] = R * cos(t);
		 vertices[i*6+4] = R * sin(t);
		 vertices[i*6+5] = 0.55 ;
	}

}

void sideOfFrontWheel()
{
    int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices2[i*6] = R2 * cos(t);
		 vertices2[i*6+1] = R2 * sin(t);
		 vertices2[i*6+2] = 0;
		 vertices2[i*6+3] = R * cos(t);
		 vertices2[i*6+4] = R * sin(t);
		 vertices2[i*6+5] = 0.1 ;

	}

}

void innerSideOfFrontWheel()
{
    int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices5[i*6] = R * cos(t);
		 vertices5[i*6+1] = R * sin(t);
		 vertices5[i*6+2] = 0 ;
		 vertices5[i*6+3] = R2 * cos(t);
		 vertices5[i*6+4] = R2 * sin(t);
		 vertices5[i*6+5] = 0.1;
	}

}


void createRearWheel()
{
	int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices3[i*6] = R3 * cos(t);
		 vertices3[i*6+1] = R3 * sin(t);
		 vertices3[i*6+2] = 0;
		 vertices3[i*6+3] = R3 * cos(t);
		 vertices3[i*6+4] = R3 * sin(t);
		 vertices3[i*6+5] = 0.55 ;

	}

}

void sideOfRearWheel()
{
    int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices4[i*6] = R4 * cos(t);
		 vertices4[i*6+1] = R4 * sin(t);
		 vertices4[i*6+2] = 0;
		 vertices4[i*6+3] = R3 * cos(t);
		 vertices4[i*6+4] = R3 * sin(t);
		 vertices4[i*6+5] = 0.1 ;
	}

}


void innerSideOfRearWheel()
{
    int i;
	float t;
    for(i=0;i<=2*numVertices;i++)
	{
		 t = (-2 * PI) + ((PI/20.0) * i);
		 vertices6[i*6] = R3 * cos(t);
		 vertices6[i*6+1] = R3 * sin(t);
		 vertices6[i*6+2] = 0 ;
		 vertices6[i*6+3] = R4 * cos(t);
		 vertices6[i*6+4] = R4 * sin(t);
		 vertices6[i*6+5] = 0.1;
	}

}


// Routine to draw a bitmap character string.
void writeBitmapString(void *font, char *string)
{  
   char *c;

   for (c = string; *c != '\0'; c++) glutBitmapCharacter(font, *c);
}

// Routine to convert floating point to char string.
void floatToString(char * destStr, int count, float val) 
{
   _snprintf(destStr,count,"%f",val);
} 

// Write data.
void writeData(void)
{
   char * tempStr0;
   char * tempStr1;
   char * tempStr2;
   char * tempStr3;
   char * tempStr4;
   char * tempStr5;


   floatToString(theStringBuffer, 4, velocity*20.0);
   glRasterPos3f(0.0, 5.0, 0.0);
   writeBitmapString((void*)font, "Speed: ");
   writeBitmapString((void*)font, theStringBuffer);
   writeBitmapString((void*)font, " mph");
   //glEnable(GL_LIGHTING); // Re-enable lighting.
   //glEnable(GL_TEXTURE_2D);
}

// Timer function.
void animate(int value)
{

	float b, d;
	float Fr ,Fd;
	float density =1.2;
	float area =1.94;
	if(omegaE <= 1000.0)
	{
		b=0.0;
		d=220.0;
	}else if(omegaE<4600.0){
		b=0.025;
		d=195.0;
	}else{
		b=-0.032;
		d=457.2;
	}

    v = sqrt(vx*vx+vy*vy+vz*vz)+1.0e-8;
  
	Fr = muR*mass*G;

	Fd = 0.5*density*Cd*area*v*v;

   if (isForce) 
   {
	  //Key is pressed
	  
	  velocity = velocity + acceleration;
	  s = s + (direction)*(velocity-(0.5*acceleration));
	  if(velocity>=0){
	     latitude = latitude +(direction)*((velocity-(0.5*acceleration))*sin((carAngle/180)*PI));
	     longitude = longitude +(direction)*((velocity-(0.5*acceleration))*cos((carAngle/180)*PI));
		 angle = (s*2*PI)/R;
		 angle2= (s*2*PI)/R3;
		 if(angle>360){ angle = (int)angle%360; }
	  } 

	  //cout<<"Lat "<<latitude<<" Long "<<longitude<<" Car Angle "<<carAngle<<endl;

      isForce = 0; // Set force to 0 - this makes it necessary to keep pressing the up key in order 
	               // to continue applying force.	  
   }
   else
   {
    
	   //Key is released 

	   if(velocity>0){
		   //if(acceleration<velocity){
		   if(direction==-1){
				velocity = velocity - 0.5*5.0*acceleration;
		   }else{
				velocity = velocity - 0.5*acceleration;
		   }
		   if(velocity<0) velocity=0;
		   //}else{ velocity = 0.0; }
	      s = s + (velocity-(0.5*acceleration));
	      latitude = latitude +((velocity-(0.5*acceleration))*sin((carAngle/180)*PI));
	      longitude = longitude +((velocity-(0.5*acceleration))*cos((carAngle/180)*PI));
		  angle = (s*2*PI)/R;
		  angle2= (s*2*PI)/R3;
		  if(angle>360){ angle = (int)angle%360; }
	   }

	   if(angleY==0) {/*do nothing*/ angleY=0;}
	   else if(angleY>=2){ angleY-=2; }
	   else if(angleY <=-2){ angleY+=2; }

	  //cout<<"Lat "<<latitude<<" Long "<<longitude<<" Car ANgle "<<carAngle<<endl;

   }

   //cout<<velocity<<endl;
   glutTimerFunc(animationPeriod, animate, 1);
   glutPostRedisplay();
}

// Initialization routine.
void setup(void) 
{
   glClearColor(0.0, 0.0, 0.0, 0.0);
   glEnable(GL_DEPTH_TEST); // Enable depth testing.

    obj = new Model();
    obj -> readObj("icecar7.obj"); 

	wheel = new Model();
	wheel -> readObj("wheel.obj");

    //obj ->draw();

   // Turn on OpenGL lighting.
   glEnable(GL_LIGHTING);

   // Light property vectors.
   float lightAmb[] = { 0.0, 0.0, 0.0, 1.0 };
   float lightDifAndSpec0[] = { 1.0, 1.0, 1.0, 1.0 };
   float lightDifAndSpec1[] = { 0.0, 1.0, 0.0, 1.0 };
   float globAmb[] = { 0.2, 0.2, 0.2, 1.0 };
   
   // Light0 properties.
   glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDifAndSpec0);
   glLightfv(GL_LIGHT0, GL_SPECULAR, lightDifAndSpec0);

   // Light1 properties.
   glLightfv(GL_LIGHT1, GL_AMBIENT, lightAmb);
   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightDifAndSpec1);
   glLightfv(GL_LIGHT1, GL_SPECULAR, lightDifAndSpec1);
   
   glEnable(GL_LIGHT0); // Enable particular light source.
   glEnable(GL_LIGHT1); // Enable particular light source.
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globAmb); // Global ambient light.
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); // Enable local viewpoint

   sideOfFrontWheel();
   createFrontWheel();
   sideOfRearWheel();
   createRearWheel();
   innerSideOfFrontWheel();
   innerSideOfRearWheel();
   glEnableClientState(GL_VERTEX_ARRAY);

}


// Drawing routine.
void drawScene(void)
{
   int i, j;

   // Light position vectors.	
   float lightPos0[] = { 0.0, 2.0, 2.5, 1.0 };
   float lightPos1[] = { 1.0, 2.0, 0.0, 1.0 };

   // Material property vectors.
   float matAmb[] = {1.0, 1.0, 1.0, 1.0};
   float matDif[] = {0.0, 0.0, w, 1.0};
   float matSpec[] = { r, r, r, 1.0 };
   float matShine[] = { h };
   float matEmission[] = {0.0, 0.0, e, 1.0};

   glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glLoadIdentity();

   // Light quadratic attenuation factor.
   glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, g);
   //glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, g);

   // Draw light source spheres after disabling lighting.
   glDisable(GL_LIGHTING);

   // Light0 and its sphere positioned.
   glPushMatrix();
   glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
   glTranslatef(lightPos0[0], lightPos0[1], lightPos0[2]);
   glColor3f(1.0, 1.0, 1.0); 
   glutWireSphere(0.05, 8, 8);
   glPopMatrix();

   // Light1 and its sphere positioned.
   glPushMatrix();
   glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);
   glTranslatef(lightPos1[0], lightPos1[1], lightPos1[2]);
   glColor3f(0.0, 1.0, 0.0); 
   glutWireSphere(0.05, 8, 8);
   glPopMatrix();

   //glEnable(GL_LIGHTING);

   // Material properties of sphere.
   glMaterialfv(GL_FRONT, GL_AMBIENT, matAmb);
   glMaterialfv(GL_FRONT, GL_DIFFUSE, matDif);
   glMaterialfv(GL_FRONT, GL_SPECULAR, matSpec);
   glMaterialfv(GL_FRONT, GL_SHININESS, matShine);
   glMaterialfv(GL_FRONT, GL_EMISSION, matEmission);


   glClear (GL_COLOR_BUFFER_BIT);
   glLoadIdentity();

   if(!cameraMode){
      gluLookAt(latitude+(zVal*cos((xVal/180)*PI)), zVal*cos((yVal/180)*PI), longitude+(zVal*sin((xVal/180)*PI)), latitude, 1.0, longitude, 0.0, 1.0, 0.0);
   }else{
      gluLookAt(latitude+3,2.0,longitude,latitude+2,1.5,longitude+3,0.0,1.0,0.0);
   }

	//writeData();

    glPushMatrix();
	glTranslatef(0.0,-1.0,0.0);
    glColor3f(0.9f, 0.9f, 0.9f);
    for(float z=-25.0; z<300.0; z+=5.0)
    {
      glBegin(GL_TRIANGLE_STRIP);
      for(float x=-50.0; x<50.0; x+=5.0)
	  {
	     glVertex3f(x, 0.0, z);
	     glVertex3f(x, 0.0, z+5.0);
	  }
       glEnd();
    }
	glPopMatrix();

   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
   //glPolygonMode(GL_FRONT, GL_LINE);
   //glPolygonMode(GL_BACK, GL_FILL);

   glColor3f(1.0, 1.0, 0.0);

   	for(i=0;i<=numVertices*2;i++)
	{
		stripIndices[i]=i;
	}


    glPushMatrix();
    glTranslatef(latitude,0,longitude);
	glTranslatef(0,0,-1);
    glRotatef(carAngle,0,1,0);
	glTranslatef(0,0,1);

	writeData();

    //Model *obj = new Model();
    //obj -> readObj("icecar7.obj"); 

	glPushMatrix();
	glScalef(0.4,0.4,0.4);
    obj ->draw();
    glPopMatrix();

	glPushMatrix();
	glTranslatef(-2.8,1.0,3.0);
	glRotatef(angle,1,0,0);
	glRotatef(90,0,0,1);
	glScalef(0.045,0.045,0.045);
	wheel -> draw();
	glPopMatrix();

	//FrontWheel
	glPushMatrix();
    glTranslatef(-3.0,-0.8,5.0);
	glRotatef(angleY,0,1,0);
    glRotatef(90,0,1,0);
	glRotatef(angle,0,0,1);
	glPushMatrix();
	glTranslatef(0.0,0.0,0.1);
    glVertexPointer(3, GL_FLOAT, 0, vertices);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glVertexPointer(3, GL_FLOAT, 0, vertices2);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPushMatrix();
	glTranslatef(0.0,0.0,0.65);
	glVertexPointer(3, GL_FLOAT, 0, vertices5);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPopMatrix();

	glPushMatrix();
    glTranslatef(3.0,-0.8,5.0);
	glRotatef(angleY,0,1,0);
    glRotatef(-90,0,1,0);
	glRotatef(-angle,0,0,1);
	glPushMatrix();
	glTranslatef(0.0,0.0,0.1);
    glVertexPointer(3, GL_FLOAT, 0, vertices);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glVertexPointer(3, GL_FLOAT, 0, vertices2);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPushMatrix();
	glTranslatef(0.0,0.0,0.65);
	glVertexPointer(3, GL_FLOAT, 0, vertices5);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPopMatrix();

	//RearWheel
    glPushMatrix();
    glTranslatef(3.0,-0.6,-4.0);
    glRotatef(-90,0,1,0);
	glRotatef(-angle2,0,0,1);
    glVertexPointer(3, GL_FLOAT, 0, vertices3);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPushMatrix();
	glTranslatef(0.0,0.0,-0.1);
    glVertexPointer(3, GL_FLOAT, 0, vertices4);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPushMatrix();
	glTranslatef(0.0,0.0,0.55);
	glVertexPointer(3, GL_FLOAT, 0, vertices6);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPopMatrix();

    glPushMatrix();
    glTranslatef(-3.0,-0.6,-4.0);
    glRotatef(90,0,1,0);
	glRotatef(angle2,0,0,1);
    glVertexPointer(3, GL_FLOAT, 0, vertices3);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPushMatrix();
	glTranslatef(0.0,0.0,-0.1);
    glVertexPointer(3, GL_FLOAT, 0, vertices4);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPushMatrix();
	glTranslatef(0.0,0.0,0.55);
	glVertexPointer(3, GL_FLOAT, 0, vertices6);
	glDrawElements(GL_TRIANGLE_STRIP, numVertices , GL_UNSIGNED_BYTE , stripIndices);
	glPopMatrix();
    glPopMatrix();

   

   glPolygonMode(GL_BACK, GL_LINE);
   glPolygonMode(GL_FRONT, GL_FILL);
   // Specify and enable the Bezier surface.
   glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 2, 0, 1, 6, 8, controlPoints[0][0]); 
   glEnable(GL_MAP2_VERTEX_3); 
   glEnable(GL_AUTO_NORMAL);
   // Make a mesh approximation of the Bezier surface.
   glColor3f (1.0, 1.0, 1.0);
   glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
   glEvalMesh2(GL_FILL, 0, 20, 0, 20);

   glPolygonMode(GL_FRONT, GL_LINE);
   glPolygonMode(GL_BACK, GL_FILL);

   glPushMatrix();
   glScalef(-1,1,1);
   glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 2, 0, 1, 6, 8, controlPoints0[0][0]); 
   glEnable(GL_MAP2_VERTEX_3); 
   glEnable(GL_AUTO_NORMAL);
   // Make a mesh approximation of the Bezier surface.
   glColor3f (1.0, 1.0, 1.0);
   glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
   glEvalMesh2(GL_FILL, 0, 20, 0, 20);
   glPopMatrix();

   // Specify and enable the Bezier surface.
   glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 6, 0, 1, 18, 8, controlPoints1[0][0]); 
   glEnable(GL_MAP2_VERTEX_3);
   glEnable(GL_AUTO_NORMAL);
   // Make a mesh approximation of the Bezier surface.
   glColor3f (1.0, 1.0, 1.0);
   glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
   glEvalMesh2(GL_FILL, 0, 20, 0, 20);


   glPushMatrix();
   glTranslatef(0.0,0.58,-5.5);
   glRotatef(-70,1,0,0);
   glTranslatef(0.0,0.0,3.0);
   glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 6, 0, 1, 18, 3, controlPoints2[0][0]); 
   glEnable(GL_MAP2_VERTEX_3);
   glEnable(GL_AUTO_NORMAL);
   glColor3f (0.0, 0.0, 1.0);
   glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
   glEvalMesh2(GL_FILL, 0, 20, 0, 20);
   glPopMatrix();

   glPushMatrix();
   glTranslatef(0.0,-1.16,-4.5);
   glRotatef(0,1,0,0);
   glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 6, 0, 1, 18, 2, controlPoints3[0][0]); 
   glEnable(GL_MAP2_VERTEX_3);
   glEnable(GL_AUTO_NORMAL);
   glColor3f (1.0, 1.0, 1.0);
   glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
   glEvalMesh2(GL_FILL, 0, 20, 0, 20);
   glPopMatrix();

   glPopMatrix();

   glutSwapBuffers();
}

// OpenGL window reshape routine.
void resize(int w, int h)
{
   glViewport(0, 0, (GLsizei)w, (GLsizei)h); 
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0, (float)w/(float)h, 1.0, 100.0);
   glMatrixMode(GL_MODELVIEW);
}

// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
   switch(key) 
   {
      case 27:
         exit(0);
         break;
      case 't':
		  if(cameraMode==0) cameraMode=1;
		  else cameraMode=0;
		  glutPostRedisplay();
		  break;
	  case 'a':
		    xVal++;
		    glutPostRedisplay();
			break;
	  case 'A':
		    xVal--;
		    glutPostRedisplay();
			break;
	  case 's':
		    yVal++;
		    glutPostRedisplay();
			break;
	  case 'S':
		    yVal--;
		    glutPostRedisplay();
			break;
	  case 'd':
		    if(zVal<20) zVal++;
		    glutPostRedisplay();
			break;
	  case 'D':
		    if(zVal>10) zVal--;
		    glutPostRedisplay();
			break;
      case 'q':
 		 if (q > 0.0) q -= 0.05;
         glutPostRedisplay();
		 break;
	  case 'Q':
 		 if (q < 1.0) q += 0.05;
         glutPostRedisplay();
		 break;
	  case 'w':
 		 if (w > 0.0) w -= 0.05;
         glutPostRedisplay();
		 break;
	  case 'W':
 		 if (w < 1.0) w += 0.05;
         glutPostRedisplay();
		 break;
	  case 'r':
 		 if (r > 0.0) r -= 0.05;
         glutPostRedisplay();
		 break;
	  case 'R':
 		 if (r < 1.0) r += 0.05;
         glutPostRedisplay();
		 break;
	  case 'e':
 		 if (e > 0.0) e -= 0.05;
         glutPostRedisplay();
		 break;
	  case 'E':
 		 if (e < 1.0) e += 0.05;
         glutPostRedisplay();
		 break;
	  case 'h':
 		 if (h > 0.0) h -= 1.0;
         glutPostRedisplay();
		 break;
	  case 'H':
 		 if (h < 128.0) h += 1.0;
         glutPostRedisplay();
		 break;
	  case 'g':
 		 if (g > 0.0) g -= 0.005;
         glutPostRedisplay();
		 break;
	  case 'G':
 		 g  += 0.005;
         glutPostRedisplay();
		 break;
      default:
         break;
   }
}


// Callback routine for non-ASCII key entry.
void specialKeys(int key, int x, int y)
{

   switch (key) {
		case GLUT_KEY_LEFT : 
			if(velocity>0){
				carAngle++;
				if(isForce==1){ isForce=1;  }
				else{ isForce=0;  }
				if(angleY<=44){angleY++;};
				if(carAngle>360){ carAngle = (int)carAngle%360; };
			}
			break;
		case GLUT_KEY_RIGHT : 
			if(velocity>0){
				carAngle--;
				if(angleY>=-44){angleY--;};
				if(carAngle>360){ carAngle = (int)carAngle%360; };
			}
			break;
		case GLUT_KEY_UP : direction=1;isForce=1;glutPostRedisplay();break;
		case GLUT_KEY_DOWN : direction=-1;isForce=0;glutPostRedisplay();break;
	}
   glutPostRedisplay();
}

// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
   cout << "============================================================="<<endl;
   cout << "Interaction:" << endl;
   cout << "============================================================="<<endl;
   cout << "Press space and tab to select a control point." << endl
        << "Press the right/left to turn car." << endl
        << "Press the up/down arrow keys to move car forward or backward." << endl
        << "Press the a, A keys to rotate the viewpoint about Y-Axis." << endl
        << "Press the s, S keys to move the view point up or down." << endl
        << "Press the d, D keys to zoom out or zoom in the viewpoint." << endl;

}

// Main routine.
int main(void)
{
   printInteraction();
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); 
   glutInitWindowSize(800, 800);
   glutInitWindowPosition(100, 100); 
   glutCreateWindow("JednipatMoonrintaAssign9Q1.cpp");
   setup(); 
   glutDisplayFunc(drawScene); 
   glutReshapeFunc(resize);  
   //glutIgnoreKeyRepeat(0);
   glutKeyboardFunc(keyInput);
   glutSpecialFunc(specialKeys);
   //glutSpecialUpFunc(releaseKeys);
   glutTimerFunc(5, animate, 1);
   glutMainLoop(); 

   return 0;  
}
